using System;

namespace Aima.Core.util.datastructure
{
    public class XYLocation
    {
        

        public enum Direction
        {
            North,
            South,
            East,
            West
        };

        private readonly int _xCoOrdinate;
        private readonly int _yCoOrdinate;

        public int XCoOrdinate
        {
            get { return _xCoOrdinate; }
        }

        public int YCoOrdinate
        {
            get { return _yCoOrdinate; }
        }

        public XYLocation(int x, int y)
        {
            _xCoOrdinate = x;
            _yCoOrdinate = y;
        }

        // Returns the location one unit left of this location.
        public XYLocation West()
        {
            return new XYLocation(_xCoOrdinate - 1, _yCoOrdinate);
        }

        // Returns the location one unit right of this location.
	    public XYLocation East()
        {
            return new XYLocation(_xCoOrdinate + 1, _yCoOrdinate);
        }

        // Returns the location one unit ahead of this location.
	    public XYLocation North()
        {
            return new XYLocation(_xCoOrdinate, _yCoOrdinate - 1);
        }

        // Returns the location one unit behind, this location.
	    public XYLocation South()
        {
            return new XYLocation(_xCoOrdinate, _yCoOrdinate + 1);
        }

        /**
	 * Returns the location one unit left of this location.
	 * 
	 * @return the location one unit left of this location.
	 */

        public XYLocation Left()
        {
            return West();
        }

        /**
	 * Returns the location one unit right of this location.
	 * 
	 * @return the location one unit right of this location.
	 */

        public XYLocation Right()
        {
            return East();
        }

        /**
	 * Returns the location one unit above this location.
	 * 
	 * @return the location one unit above this location.
	 */

        public XYLocation Up()
        {
            return North();
        }

        /**
	 * Returns the location one unit below this location.
	 * 
	 * @return the location one unit below this location.
	 */

        public XYLocation Down()
        {
            return South();
        }

        /**
	 * Returns the location one unit from this location in the specified
	 * direction.
	 * 
	 * @return the location one unit from this location in the specified
	 *         direction.
	 */

        public XYLocation LocationAt(Direction direction)
        {
            if (direction.Equals(Direction.North))
            {
                return North();
            }
            if (direction.Equals(Direction.South))
            {
                return South();
            }
            if (direction.Equals(Direction.East))
            {
                return East();
            }
            if (direction.Equals(Direction.West))
            {
                return West();
            }
            throw new Exception("Unknown direction " + direction);
        }


        public override bool Equals(Object o)
        {
            
            var anotherLoc = o as XYLocation;
            if (anotherLoc == null) return false;
            return ((anotherLoc.XCoOrdinate == _xCoOrdinate) && (anotherLoc.YCoOrdinate == _yCoOrdinate));
        }


        public override String ToString()
        {
            return " ( " + _xCoOrdinate + " , " + _yCoOrdinate + " ) ";
        }


        public override int GetHashCode()
        {
            int result = 17;
            result = 37*result + _xCoOrdinate;
            result = result + _yCoOrdinate;
            return result;
        }
    }
}